/**
 * WYSIWYG - jQuery plugin 0.7
 *
 * Copyright (c) 2008-2009 Juan M Martinez
 * http://plugins.jquery.com/project/jWYSIWYG
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Id: $
 */

/*jslint browser: true, forin: true */

// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name jquery.wysiwyg.min.js
// @code_url http://jwysiwyg.googlecode.com/svn/trunk/jwysiwyg/jquery.wysiwyg.js
// ==/ClosureCompiler==

(function( $ )
{
        /**
         * @constructor
         * @private
         */
        var Wysiwyg = function( element, options )
        {
                this.init(element, options);
        };

        $['fn']['document'] = function()
        {
                var element = this.get(0);

                if ( element.nodeName.toLowerCase() == 'iframe' )
                {
                        return element.contentWindow.document;
                        /*
                        return ( $.browser.msie )
                                ? document.frames[element.id].document
                                : element.contentWindow.document // contentDocument;
                         */
                }
                return this;
        };

        $['fn']['documentSelection'] = function()
        {
                var element = this.get(0);

                if ( element.contentWindow.document.selection )
                {
                        return element.contentWindow.document.selection.createRange().text;
                }
                else
                {
                        return element.contentWindow.getSelection().toString();
                }
        };

        $['fn']['wysiwyg'] = function( options )
        {
                if ( arguments.length > 0 && arguments[0].constructor == String )
                {
                        var action = arguments[0].toString();
                        var params = [];

                        for ( var i = 1; i < arguments.length; i++ )
                        {
                                params[i - 1] = arguments[i];
                        }
                        if (action in Wysiwyg)
                        {
                                return this.each(function()
                                {
                                        $.data(this, 'wysiwyg').designMode();

                                        Wysiwyg[action].apply(this, params);
                                });
                        }
                        else
                        {
                                return this;
                        }
                }

                var controls = {};

                /**
                 * If the user set custom controls, we catch it, and merge with the
                 * defaults controls later.
                 */
                if (options && options['controls'])
                {
                        controls = options['controls'];
                        delete options['controls'];
                }

                options = $.extend({
                        "html": '<'+'?xml version="1.0" encoding="UTF-8"?'+'><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">STYLE_SHEET</head><body style="margin: 0px;">INITIAL_CONTENT</body></html>',
                        "css": {},

                        "debug": false,

                        "autoSave" : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=11
                        "rmUnwantedBr" : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=15
                        "brIE" : true,

                        "controls" : {},
                        "messages" : {}
                }, options);

                options['messages'] = $.extend(true, options['messages'], Wysiwyg['MSGS_EN']);
                options['controls'] = $.extend(true, options['controls'], Wysiwyg['TOOLBAR']);

                for (var control in controls)
                {
                        if (control in options['controls'])
                        {
                                $.extend(options['controls'][control], controls[control]);
                        }
                        else
                        {
                                options['controls'][control] = controls[control];
                        }
                }

                // not break the chain
                return this.each(function()
                {
                        new Wysiwyg(this, options);
                });
        };

        $.extend(Wysiwyg, {
                "insertImage" : function( szURL, attributes )
                {
                        var self = $.data(this, 'wysiwyg');

                        if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
                        {
                                if ($.browser.msie)
                                {
                                        self.focus();
                                }
                                if ( attributes )
                                {
                                        self.editorDoc.execCommand('insertImage', false, '#jwysiwyg#');
                                        var img = self.getElementByAttributeValue('img', 'src', '#jwysiwyg#');

                                        if ( img )
                                        {
                                                img.src = szURL;

                                                for ( var attribute in attributes )
                                                {
                                                        img.setAttribute(attribute, attributes[attribute]);
                                                }
                                        }
                                }
                                else
                                {
                                        self.editorDoc.execCommand('insertImage', false, szURL);
                                }
                        }
                },

                "createLink" : function( szURL )
                {
                        var self = $.data(this, 'wysiwyg');

                        if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
                        {
                                var selection = $(self.editor).documentSelection();

                                if ( selection.length > 0 )
                                {
                                        if ($.browser.msie)
                                        {
                                                self.focus();
                                        }
                                        self.editorDoc.execCommand('unlink', false, []);
                                        self.editorDoc.execCommand('createLink', false, szURL);
                                }
                                else if ( self.options.messages.nonSelection )
                                {
                                        alert(self.options.messages.nonSelection);
                                }
                        }
                },

                "insertHtml" : function( szHTML )
                {
                        var self = $.data(this, 'wysiwyg');

                        if ( self.constructor == Wysiwyg && szHTML && szHTML.length > 0 )
                        {
                                self.focus();
                                if ($.browser.msie)
                                {
                                        self.editorDoc.execCommand('insertImage', false, '#jwysiwyg#');
                                        var img = self.getElementByAttributeValue('img', 'src', '#jwysiwyg#');
                                        if (img)
                                        {
                                                $(img).replaceWith(szHTML);
                                        }
                                }
                                else
                                {
                                        self.editorDoc.execCommand('insertHTML', false, szHTML);
                                }
                        }
                },

                "setContent" : function( newContent )
                {
                        var self = $.data(this, 'wysiwyg');
                                self.setContent( newContent );
                                self.saveContent();
                },

                "clear" : function()
                {
                        var self = $.data(this, 'wysiwyg');
                                self.setContent('');
                                self.saveContent();
                },

                "MSGS_EN" : {
                        "nonSelection" : 'select the text you wish to link'
                },

                "TOOLBAR" : {
                        "bold"          : { "visible" : true, "tags" : ['b', 'strong'], "css" : { "fontWeight" : 'bold' }, "tooltip" : "Bold" },
                        "italic"        : { "visible" : true, "tags" : ['i', 'em'], "css" : { "fontStyle": 'italic' }, "tooltip" : "Italic" },
                        "strikeThrough" : { "visible" : true, "tags" : ['s', 'strike'], "css" : { "textDecoration" : 'line-through' }, "tooltip" : "Strike-through" },
                        "underline"     : { "visible" : true, "tags" : ['u'], "css" : { "textDecoration" : 'underline' }, "tooltip" : "Underline" },

                        separator00 : { "visible": true, "separator": true },

                        "justifyLeft"   : { "visible": true, "css": { "textAlign": 'left' }, "tooltip": "Justify Left" },
                        "justifyCenter" : { "visible": true, "tags": ['center'], "css": { "textAlign": 'center' }, "tooltip": "Justify Center" },
                        "justifyRight"  : { "visible": true, "css": { "textAlign": 'right' }, "tooltip": "Justify Right" },
                        "justifyFull"   : { "visible": true, "css": { "textAlign": 'justify' }, "tooltip": "Justify Full" },

                        separator01 : { "visible": true, "separator": true },

                        "indent"  : { "visible": true, "tooltip": "Indent" },
                        "outdent" : { "visible": true, "tooltip": "Outdent" },

                        separator02 : { "visible": false, "separator": true },

                        "subscript"   : { "visible": true, "tags": ['sub'], "tooltip": "Subscript" },
                        "superscript" : { "visible": true, "tags": ['sup'], "tooltip": "Superscript" },

                        separator03 : { "visible": true, "separator": true },

                        "undo" : { "visible": true, "tooltip": "Undo" },
                        "redo" : { "visible": true, "tooltip": "Redo" },

                        separator04 : { "visible": true, "separator": true },

                        "insertOrderedList"    : { "visible": true, "tags": ['ol'], "tooltip": "Insert Ordered List" },
                        "insertUnorderedList"  : { "visible": true, "tags": ['ul'], "tooltip": "Insert Unordered List" },
                        "insertHorizontalRule" : { "visible": true, "tags": ['hr'], "tooltip": "Insert Horizontal Rule" },

                        separator05 : { "separator": true },

                        "createLink" : {
                                "visible": true,
                                "exec"   : function()
                                {
                                        var selection = $(this.editor).documentSelection();

                                        if ( selection.length > 0 )
                                        {
                                                if ( $.browser.msie )
                                                {
                                                        this.focus();
                                                        this.editorDoc.execCommand('createLink', true, null);
                                                }
                                                else
                                                {
                                                        var szURL = prompt('URL', 'http://');

                                                        if ( szURL && szURL.length > 0 )
                                                        {
                                                                this.editorDoc.execCommand('unlink', false, []);
                                                                this.editorDoc.execCommand('createLink', false, szURL);
                                                        }
                                                }
                                        }
                                        else if ( this.options.messages.nonSelection )
                                        {
                                                alert(this.options.messages.nonSelection);
                                        }
                                },
                                "tags": ['a'],
                                "tooltip": "Create link"
                        },

                        "insertImage" : {
                                "visible": true,
                                "exec"   : function()
                                {
                                        if ( $.browser.msie )
                                        {
                                                this.focus();
                                                this.editorDoc.execCommand('insertImage', true, null);
                                        }
                                        else
                                        {
                                                var szURL = prompt('URL', 'http://');

                                                if ( szURL && szURL.length > 0 )
                                                {
                                                        this.editorDoc.execCommand('insertImage', false, szURL);
                                                }
                                        }
                                },
                                "tags": ['img'],
                                "tooltip": "Insert image"
                        },

                        separator06 : { "separator": true },

                        "h1mozilla" : { "visible": true && $.browser.mozilla, "className": 'h1', "command": 'heading', arguments : ['h1'], "tags": ['h1'], "tooltip": "Header 1" },
                        "h2mozilla" : { "visible": true && $.browser.mozilla, "className": 'h2', "command": 'heading', arguments : ['h2'], "tags": ['h2'], "tooltip": "Header 2" },
                        "h3mozilla" : { "visible": true && $.browser.mozilla, "className": 'h3', "command": 'heading', arguments : ['h3'], "tags": ['h3'], "tooltip": "Header 3" },

                        "h1" : { "visible": true && !( $.browser.mozilla ), "className": 'h1', "command": 'formatBlock', arguments : ['<H1>'], "tags": ['h1'], "tooltip": "Header 1" },
                        "h2" : { "visible": true && !( $.browser.mozilla ), "className": 'h2', "command": 'formatBlock', arguments : ['<H2>'], "tags": ['h2'], "tooltip": "Header 2" },
                        "h3" : { "visible": true && !( $.browser.mozilla ), "className": 'h3', "command": 'formatBlock', arguments : ['<H3>'], "tags": ['h3'], "tooltip": "Header 3" },

                        separator07 : { "visible": false, "separator": true },

                        "cut"   : { "visible": false, "tooltip": "Cut" },
                        "copy"  : { "visible": false, "tooltip": "Copy" },
                        "paste" : { "visible": false, "tooltip": "Paste" },

                        separator08 : { "separator": false && !( $.browser.msie ) },

                        "increaseFontSize" : { "visible": false && !( $.browser.msie ), "tags": ['big'], "tooltip": "Increase font size" },
                        "decreaseFontSize" : { "visible": false && !( $.browser.msie ), "tags": ['small'], "tooltip": "Decrease font size" },

                        separator09 : { "separator": true },

                        "html" : {
                                "visible" : false,
                                "exec"    : function()
                                {
                                        if ( this.viewHTML )
                                        {
                                                this.setContent( $(this.original).val() );
                                                $(this.original).hide();
                                        }
                                        else
                                        {
                                                this.saveContent();
                                                $(this.original).show();
                                        }

                                        this.viewHTML = !( this.viewHTML );
                                },
                                "tooltip": "View source code"
                        },

                        "removeFormat" : {
                                "visible": true,
                                "exec"   : function()
                                {
                                        if ($.browser.msie)
                                        {
                                                this.focus();
                                        }
                                        this.editorDoc.execCommand('removeFormat', false, []);
                                        this.editorDoc.execCommand('unlink', false, []);
                                },
                                "tooltip": "Remove formatting"
                        }
                }
        });

        $.extend(Wysiwyg.prototype,
        {
                original : null,
                options  : {},

                element  : null,
                editor   : null,

                focus : function()
                {
                        $(this.editorDoc.body).focus();
                },

                init : function( element, options )
                {
                        var self = this;

                        this.editor = element;
                        this.options = options || {};

                        $.data(element, 'wysiwyg', this);

                        var newX = element.width || element.clientWidth || 0;
                        var newY = element.height || element.clientHeight || 0;

                        if ( element.nodeName.toLowerCase() == 'textarea' )
                        {
                                this.original = element;

                                if ( newX == 0 && element.cols )
                                {
                                        newX = ( element.cols * 8 ) + 21;
                                }
                                if ( newY == 0 && element.rows )
                                {
                                        newY = ( element.rows * 16 ) + 16;
                                }
                                this.editor = $('<iframe src="javascript:false;"></iframe>').css({
                                        minHeight : ( newY - 6 ).toString() + 'px',
                                        width    : ( newX - 8 ).toString() + 'px'
                                }).attr('id', $(element).attr('id') + 'IFrame')
                                        .attr('frameborder', '0')
                                        ;

                                /**
                                 * http://code.google.com/p/jwysiwyg/issues/detail?id=96
                                 */
                                this.editor.attr('tabindex', $(element).attr('tabindex'));

                                if ( $.browser.msie )
                                {
                                        this.editor
                                                .css('height', ( newY ).toString() + 'px');

                                        /**
                                        var editor = $('<span></span>').css({
                                                width    : ( newX - 6 ).toString() + 'px',
                                                height  : ( newY - 8 ).toString() + 'px'
                                        }).attr('id', $(element).attr('id') + 'IFrame');

                                        editor.outerHTML = this.editor.outerHTML;
                                         */
                                }
                        }

                        var panel = this.panel = $('<ul role="menu" class="panel"></ul>');

                        this.appendControls();
                        this.element = $('<div></div>').css({
                                width : ( newX > 0 ) ? ( newX ).toString() + 'px' : '100%'
                        }).addClass('wysiwyg')
                                .append(panel)
                                .append( $('<div><!-- --></div>').css({ clear : 'both' }) )
                                .append(this.editor)
                                ;

                        $(element)
                                .hide()
                                .before(this.element)
                                ;

                        this.viewHTML = false;
                        this.initialHeight = newY - 8;

                        /**
                         * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
                         */
                        this.initialContent = $(element).val();
                        this.initFrame();

                        if ( this.initialContent.length === 0 )
                        {
                                this.setContent('');
                        }

                        /**
                         * http://code.google.com/p/jwysiwyg/issues/detail?id=100
                         */
                        var form = $(element).closest('form');

                        if ( this.options.autoSave )
                        {
                                form.submit(function() { self.saveContent(); });
                        }

                        form.bind('reset', function()
                        {
                                self.setContent( self.initialContent );
                                self.saveContent();
                        });
                },

                initFrame : function()
                {
                        var self = this;
                        var style = '';

                        /**
                         * @link http://code.google.com/p/jwysiwyg/issues/detail?id=14
                         */
                        if ( this.options.css && this.options.css.constructor == String )
                        {
                                style = '<link rel="stylesheet" type="text/css" media="screen" href="' + this.options.css + '" />';
                        }

                        this.editorDoc = $(this.editor).document();
                        this.editorDoc_designMode = false;

                        try
                        {
                                this.editorDoc.designMode = 'on';
                                this.editorDoc_designMode = true;
                        } catch ( e )
                        {
                                // Will fail on Gecko if the editor is placed in an hidden container element
                                // The design mode will be set ones the editor is focused

                                $(this.editorDoc).focus(function()
                                {
                                        self.designMode();
                                });
                        }

                        this.editorDoc.open();
                        this.editorDoc.write(
                                this.options.html
                                        /**
                                         * @link http://code.google.com/p/jwysiwyg/issues/detail?id=144
                                         */
                                        .replace(/INITIAL_CONTENT/, function() { return self.initialContent; })
                                        .replace(/STYLE_SHEET/, function() { return style; })
                        );
                        this.editorDoc.close();

                        this.editorDoc.contentEditable = 'true';

                        if ( $.browser.msie )
                        {
                                /**
                                 * Remove the horrible border it has on IE.
                                 */
                                window.setTimeout(function() { $(self.editorDoc.body).css('border', 'none'); }, 0);
                        }

                        $(this.editorDoc).click(function( event )
                        {
                                self.checkTargets( event.target ? event.target : event.srcElement);
                        });

                        /**
                         * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
                         */
                        $(this.original).focus(function()
                        {
                                if (!$.browser.msie)
                                {
                                        self.focus();
                                }
                        });

                        if (!$.browser.msie)
                        {
                                $(this.editorDoc).keydown(function(event)
                                {
                                        if (event.ctrlKey)
                                        {
                                                switch (event.keyCode)
                                                {
                                                case 66: // Ctrl + B
                                                        this.execCommand('Bold', false, false);
                                                        return false;
                                                case 73: // Ctrl + I
                                                        this.execCommand('Italic', false, false);
                                                        return false;
                                                case 85: // Ctrl + U
                                                        this.execCommand('Underline', false, false);
                                                        return false;
                                                }
                                        }
                                        return true;
                                });
                        }
                        else if (this.options.brIE)
                        {
                                $(this.editorDoc).keydown(function(event)
                                {
                                        if (event.keyCode == 13)
                                        {
                                                var rng = self.getRange();
                                                rng.pasteHTML('<br />');
                                                rng.collapse(false);
                                                rng.select();
                                                return false;
                                        }
                                        return true;
                                });
                        }

                        if ( this.options.autoSave )
                        {
                                /**
                                 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=11
                                 */
                                $(this.editorDoc).keydown(function() { self.saveContent(); })
                                        .keyup(function() { self.saveContent(); })
                                        .mousedown(function() { self.saveContent(); })
                                        ;
                        }

                        if ( this.options.css )
                        {
                                window.setTimeout(function()
                                {
                                        if (self.options.css.constructor == String)
                                        {
                                                /**
                                                 * $(self.editorDoc)
                                                 * .find('head')
                                                 * .append(
                                                 *       $('<link rel="stylesheet" type="text/css" media="screen" />')
                                                 *       .attr('href', self.options.css)
                                                 * );
                                                 */
                                        }
                                        else
                                        {
                                                $(self.editorDoc).find('body').css(self.options.css);
                                        }
                                }, 0);
                        }
                },

                designMode : function()
                {
                        if (!(this.editorDoc_designMode))
                        {
                                try {
                                        this.editorDoc.designMode = 'on';
                                        this.editorDoc_designMode = true;
                                } catch ( e ) {}
                        }
                },

                getSelection : function()
                {
                        return ( window.getSelection ) ? window.getSelection() : document.selection;
                },

                getRange : function()
                {
                        var selection = this.getSelection();

                        if (!(selection))
                        {
                                return null;
                        }

                        return ( selection.rangeCount > 0 ) ? selection.getRangeAt(0) : selection.createRange();
                },

                getContent : function()
                {
                        return $( $(this.editor).document() ).find('body').html();
                },

                setContent : function( newContent )
                {
                        $( $(this.editor).document() ).find('body').html(newContent);
                },

                saveContent : function()
                {
                        if ( this.original )
                        {
                                var content = this.getContent();

                                if ( this.options.rmUnwantedBr )
                                {
                                        content = ( content.substr(-4) == '<br>' ) ? content.substr(0, content.length - 4) : content;
                                }

                                $(this.original).val(content);
                        }
                },

                withoutCss: function()
                {
                        if ($.browser.mozilla)
                        {
                                try
                                {
                                        this.editorDoc.execCommand('styleWithCSS', false, false);
                                }
                                catch (e)
                                {
                                        try
                                        {
                                                this.editorDoc.execCommand('useCSS', false, true);
                                        }
                                        catch (e2)
                                        {
                                        }
                                }
                        }
                },

                appendMenu : function( cmd, args, className, fn, tooltip )
                {
                        var self = this;
                        args = args || [];

                        $('<li></li>').append(
                                $('<a role="menuitem" tabindex="-1" href="javascript:;">' + (className || cmd) + '</a>')
                                        .addClass(className || cmd)
                                        .attr('title', tooltip)
                        ).click(function() {
                                if ( fn )
                                {
                                        fn.apply(self);
                                }
                                else
                                {
                                        self.withoutCss();
                                        self.editorDoc.execCommand(cmd, false, args);
                                }
                                if ( self.options.autoSave )
                                {
                                        self.saveContent();
                                }
                        }).appendTo( this.panel );
                },

                appendMenuSeparator : function()
                {
                        $('<li role="separator" class="separator"></li>').appendTo( this.panel );
                },

                appendControls : function()
                {
                        for ( var name in this.options.controls )
                        {
                                var control = this.options.controls[name];

                                if ( control.separator )
                                {
                                        if ( control.visible !== false )
                                        {
                                                this.appendMenuSeparator();
                                        }
                                }
                                else if ( control.visible )
                                {
                                        this.appendMenu(
                                                control.command || name, control.arguments || [],
                                                control.className || control.command || name || 'empty', control.exec,
                                                control.tooltip || control.command || name || ''
                                        );
                                }
                        }
                },

                checkTargets : function( element )
                {
                        for ( var name in this.options.controls )
                        {
                                var control = this.options.controls[name];
                                var className = control.className || control.command || name || 'empty';

                                $('.' + className, this.panel).removeClass('active');

                                if ( control.tags )
                                {
                                        var elm = element;
                                        do
                                        {
                                                if ( elm.nodeType != 1 )
                                                {
                                                        break;
                                                }

                                                if ( $.inArray(elm.tagName.toLowerCase(), control.tags) != -1 )
                                                {
                                                        $('.' + className, this.panel).addClass('active');
                                                }
                                        } while ((elm = elm.parentNode));
                                }

                                if ( control.css )
                                {
                                        var el = $(element);

                                        do
                                        {
                                                if ( el[0].nodeType != 1 )
                                                {
                                                        break;
                                                }

                                                for ( var cssProperty in control.css )
                                                {
                                                        if ( el.css(cssProperty).toString().toLowerCase() == control.css[cssProperty] )
                                                        {
                                                                $('.' + className, this.panel).addClass('active');
                                                        }
                                                }
                                        } while ((el = el.parent()));
                                }
                        }
                },

                getElementByAttributeValue : function( tagName, attributeName, attributeValue )
                {
                        var elements = this.editorDoc.getElementsByTagName(tagName);

                        for ( var i = 0; i < elements.length; i++ )
                        {
                                var value = elements[i].getAttribute(attributeName);

                                if ( $.browser.msie )
                                {
                                        /** IE add full path, so I check by the last chars. */
                                        value = value.substr(value.length - attributeValue.length);
                                }

                                if ( value == attributeValue )
                                {
                                        return elements[i];
                                }
                        }

                        return false;
                }
        });
})(jQuery);
